| Conditions | 16 |
| Paths | 8910 |
| Total Lines | 69 |
| Lines | 0 |
| Ratio | 0 % |
| Changes | 0 | ||
Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.
For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.
Commonly applied refactorings include:
If many parameters/temporary variables are present:
Complex classes like Aes.Ctr.encrypt often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes.
Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.
| 1 | /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ |
||
| 38 | Aes.Ctr.encrypt = function(plaintext, password, nBits) { |
||
| 39 | var blockSize = 16; // block size fixed at 16 bytes / 128 bits (Nb=4) for AES |
||
| 40 | if (!(nBits==128 || nBits==192 || nBits==256)) throw new Error('Key size is not 128 / 192 / 256'); |
||
| 41 | plaintext = String(plaintext).utf8Encode(); |
||
| 42 | password = String(password).utf8Encode(); |
||
| 43 | |||
| 44 | // use AES itself to encrypt password to get cipher key (using plain password as source for key |
||
| 45 | // expansion) - gives us well encrypted key (though hashed key might be preferred for prod'n use) |
||
| 46 | var nBytes = nBits/8; // no bytes in key (16/24/32) |
||
| 47 | var pwBytes = new Array(nBytes); |
||
| 48 | for (var i=0; i<nBytes; i++) { // use 1st 16/24/32 chars of password for key |
||
| 49 | pwBytes[i] = i<password.length ? password.charCodeAt(i) : 0; |
||
| 50 | } |
||
| 51 | var key = Aes.cipher(pwBytes, Aes.keyExpansion(pwBytes)); // gives us 16-byte key |
||
| 52 | key = key.concat(key.slice(0, nBytes-16)); // expand key to 16/24/32 bytes long |
||
| 53 | |||
| 54 | // initialise 1st 8 bytes of counter block with nonce (NIST SP800-38A §B.2): [0-1] = millisec, |
||
| 55 | // [2-3] = random, [4-7] = seconds, together giving full sub-millisec uniqueness up to Feb 2106 |
||
| 56 | var counterBlock = new Array(blockSize); |
||
| 57 | |||
| 58 | var nonce = (new Date()).getTime(); // timestamp: milliseconds since 1-Jan-1970 |
||
| 59 | var nonceMs = nonce%1000; |
||
| 60 | var nonceSec = Math.floor(nonce/1000); |
||
| 61 | var nonceRnd = Math.floor(Math.random()*0xffff); |
||
| 62 | // for debugging: nonce = nonceMs = nonceSec = nonceRnd = 0; |
||
| 63 | |||
| 64 | for (var i=0; i<2; i++) counterBlock[i] = (nonceMs >>> i*8) & 0xff; |
||
| 65 | for (var i=0; i<2; i++) counterBlock[i+2] = (nonceRnd >>> i*8) & 0xff; |
||
| 66 | for (var i=0; i<4; i++) counterBlock[i+4] = (nonceSec >>> i*8) & 0xff; |
||
| 67 | |||
| 68 | // and convert it to a string to go on the front of the ciphertext |
||
| 69 | var ctrTxt = ''; |
||
| 70 | for (var i=0; i<8; i++) ctrTxt += String.fromCharCode(counterBlock[i]); |
||
| 71 | |||
| 72 | // generate key schedule - an expansion of the key into distinct Key Rounds for each round |
||
| 73 | var keySchedule = Aes.keyExpansion(key); |
||
| 74 | |||
| 75 | var blockCount = Math.ceil(plaintext.length/blockSize); |
||
| 76 | var ciphertext = ''; |
||
| 77 | |||
| 78 | for (var b=0; b<blockCount; b++) { |
||
| 79 | // set counter (block #) in last 8 bytes of counter block (leaving nonce in 1st 8 bytes) |
||
| 80 | // done in two stages for 32-bit ops: using two words allows us to go past 2^32 blocks (68GB) |
||
| 81 | for (var c=0; c<4; c++) counterBlock[15-c] = (b >>> c*8) & 0xff; |
||
| 82 | for (var c=0; c<4; c++) counterBlock[15-c-4] = (b/0x100000000 >>> c*8); |
||
| 83 | |||
| 84 | var cipherCntr = Aes.cipher(counterBlock, keySchedule); // -- encrypt counter block -- |
||
| 85 | |||
| 86 | // block size is reduced on final block |
||
| 87 | var blockLength = b<blockCount-1 ? blockSize : (plaintext.length-1)%blockSize+1; |
||
| 88 | var cipherChar = new Array(blockLength); |
||
| 89 | |||
| 90 | for (var i=0; i<blockLength; i++) { |
||
| 91 | // -- xor plaintext with ciphered counter char-by-char -- |
||
| 92 | cipherChar[i] = cipherCntr[i] ^ plaintext.charCodeAt(b*blockSize+i); |
||
| 93 | cipherChar[i] = String.fromCharCode(cipherChar[i]); |
||
| 94 | } |
||
| 95 | ciphertext += cipherChar.join(''); |
||
| 96 | |||
| 97 | // if within web worker, announce progress every 1000 blocks (roughly every 50ms) |
||
| 98 | if (typeof WorkerGlobalScope != 'undefined' && self instanceof WorkerGlobalScope) { |
||
| 99 | if (b%1000 == 0) self.postMessage({ progress: b/blockCount }); |
||
| 100 | } |
||
| 101 | } |
||
| 102 | |||
| 103 | ciphertext = (ctrTxt+ciphertext).base64Encode(); |
||
| 104 | |||
| 105 | return ciphertext; |
||
| 106 | }; |
||
| 107 | |||
| 226 |